package com.fastfly.domain;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Transient;

import com.fastfly.service.FastFlyException;

@Entity
public class Reservation extends BaseEntity {

	public static final int MILES_NEED_PER_ROUNDTRIP_TICKET = 25000;

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	public static final String PAYMENT_TYPE_CREDIT_CARD = "Credit Card";
	public static final String PAYMENT_TYPE_MILES = "Miles";

	@ManyToOne
	protected Customer customer;

	protected double price;
	protected String number;
	protected String paymentType;
	protected Date purchaseDate;
	
	@ManyToOne
	protected Flight departureFlight;
	
	@ManyToOne
	protected Flight returnFlight;	
	
	

	@OneToMany(mappedBy="reservation", cascade=CascadeType.ALL, fetch=FetchType.EAGER)
	protected List<Ticket> ticketCollection = new ArrayList<Ticket>();
	
	protected static char[] numberPrefixChar = {65, 65};

	
	
	public Reservation() {		
	}
	
	

	public Reservation(Customer customer, String paymentType) {	
		this.customer = customer;
		this.paymentType = paymentType;
		String numberPrefix = String.valueOf(numberPrefixChar);
		this.number = numberPrefix + getRandomStr();
		purchaseDate = new Date();		
		nextLetter(numberPrefixChar);
	}

	
	
	/**
	 * Get next letter from AA to ZZ (using the ASCII range from 65 to 90)
	 */	
	protected static void nextLetter(char[] var) {
		var[1] = (char)(var[1] + 1);		
		if (var[1] > 90) {
			var[1] = (char)(var[1] - 26);
			var[0] += 1;			
		}		
	}


	public String getNumber() {
		return number;
	}


	public Customer getCustomer() {
		return customer;
	}

	public void setCustomer(Customer customer) {
		this.customer = customer;
	}

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}

	public String getPaymentType() {
		return paymentType;
	}

	public void setPaymentType(String paymentType) {
		this.paymentType = paymentType;
	}

	public Date getPurchaseDate() {
		return purchaseDate;
	}

	public void setPurchaseDate(Date purchaseDate) {
		this.purchaseDate = purchaseDate;
	}

	public List<Ticket> getTicketCollection() {
		return ticketCollection;
	}

	public void addTicket(Ticket ticket) {
		price += ticket.getPrice();
		this.ticketCollection.add(ticket);
		ticket.setReservation(this);
	}
	
	
	//public void bookFlight(int numberPassengers, Reservation reservation, Flight flightDeparting, Flight flightReturning) {
	public void bookFlight(int numberPassengers, Reservation reservation, List<Seat> listDepartingSeats, List<Seat> listReturningSeats) {
		if (listDepartingSeats.size() < numberPassengers || listReturningSeats.size() < numberPassengers ) {
			throw new FastFlyException("There is not enough seats avaiable in flights");
		}
		
		int milesRequired = numberPassengers * MILES_NEED_PER_ROUNDTRIP_TICKET;
		if ( Reservation.PAYMENT_TYPE_MILES.equalsIgnoreCase(reservation.getPaymentType()) && (milesRequired) > customer.getMilesAccumulated() ) {
			throw new FastFlyException("Sorry, you don't have enough miles. You need " + milesRequired + " miles but you only have " + customer.getMilesAccumulated() );
		}
		
		departureFlight = listDepartingSeats.get(0).getFlight();
		returnFlight = listReturningSeats.get(0).getFlight();
		
		for (int i = 0; i < numberPassengers; i++) {
			Ticket t = new Ticket(listDepartingSeats.get(i), listReturningSeats.get(i));
			reservation.addTicket(t);						
		}
		
		customer.addReservation(this);
	}



	public Flight getDepartureFlight() {
		return departureFlight;
	}



	public void setDepartureFlight(Flight departureFlight) {
		this.departureFlight = departureFlight;
	}



	public Flight getReturnFlight() {
		return returnFlight;
	}



	public void setReturnFlight(Flight returnFlight) {
		this.returnFlight = returnFlight;
	}



	/**
	 * This method return a list of old seats to be persisted
	 */
	public List<Seat> changeSeats(Map<Long, Seat> departureMap, Map<Long, Seat> returnMap) {
		List<Seat> oldSeats = new ArrayList<Seat>();
		for (Ticket t : ticketCollection) {
			if (! (t.newSeatDepartureId == t.seatInDepartureFlight.getId().longValue()) ) {
				oldSeats.add( t.getSeatInDepartureFlight() );
				t.setSeatInDepartureFlight( departureMap.get(t.newSeatDepartureId) );				
			}
			
			if (! (t.newSeatReturningId == t.seatInReturnFlight.getId().longValue()) ) {
				oldSeats.add( t.getSeatInReturnFlight() );
				t.setSeatInReturnFlight( returnMap.get( t.newSeatReturningId) );				
			}									
		}
		return oldSeats;
	}
	
	@Transient
	public boolean isOld() {
		boolean ret = false;
		ret = departureFlight.getDepartureDate().before( (new Date()) );		
		return ret;
	}



	public void cancel() {
		for (Ticket ticket : getTicketCollection()) {
			ticket.getSeatInDepartureFlight().setStatus(Seat.AVAILABLE_STATUS);			
			ticket.getSeatInReturnFlight().setStatus(Seat.AVAILABLE_STATUS);
			int miles = customer.getMilesAccumulated();
			int milesToSubtract = ticket.getSeatInDepartureFlight().getFlight().getFlightMiles() + ticket.getSeatInReturnFlight().getFlight().getFlightMiles();
			customer.setMilesAccumulated(miles - milesToSubtract);
		}		
	}
	
	


}
